﻿// <copyright file="DomainProvinceImporter.cs" company="Gravity Age Studios">
// Code released under the MIT license (see License.txt).
// </copyright>
// <author>Vicente Cartas Espinel</author>
// <email>vicente.cartas@gmail.com</email>
namespace LightSwitchApplication.Import
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;

    internal class DomainProvinceImporter : BaseImporter<DomainProvince>
    {
        private readonly int Province = 0;
        private readonly int Domain = 1;
        private readonly int Population = 2;
        private readonly int Fortification = 3;
        private readonly int Taxes = 4;
        private readonly int Law = 5;
        private readonly int Temples = 6;
        private readonly int Guilds = 7;
        private readonly int Sources = 8;
        private readonly int Race = 9;
        private readonly int PublicInformation = 10;
        private readonly int OwnerInformation = 11;
        private readonly int GMInformation = 12;

        private IEnumerable<Domain> domains;
        private IEnumerable<Race> races;

        public DomainProvinceImporter(DataWorkspace workspace)
            : base(workspace)
        {
        }

        protected override void FetchRequisites()
        {
            this.domains = this.workspace.ApplicationData.Domains.GetQuery().Execute();
            this.races = this.workspace.ApplicationData.Races.GetQuery().Execute();

            // Overwrite the builder function, as DomainProvinces are only created when a BaseProvince is created
            this.builder = () => null;
        }

        protected override bool SkipEntity(int index)
        {
            return false;
        }

        protected override int?[] MapHeaders(string[] stringHeaders)
        {
            int?[] headers = new int?[13];

            for (int i = 0; i < stringHeaders.Length; i++)
            {
                if (stringHeaders[i].StartsWith("Prov", StringComparison.InvariantCultureIgnoreCase))
                {
                    headers[Province] = i;
                }
                else if (stringHeaders[i].StartsWith("Dom", StringComparison.InvariantCultureIgnoreCase))
                {
                    headers[Domain] = i;
                }
                else if (stringHeaders[i].StartsWith("Pop", StringComparison.InvariantCultureIgnoreCase))
                {
                    headers[Population] = i;
                }
                else if (stringHeaders[i].StartsWith("For", StringComparison.InvariantCultureIgnoreCase))
                {
                    headers[Fortification] = i;
                }
                else if (stringHeaders[i].StartsWith("Tax", StringComparison.InvariantCultureIgnoreCase))
                {
                    headers[Taxes] = i;
                }
                else if (stringHeaders[i].StartsWith("Law", StringComparison.InvariantCultureIgnoreCase))
                {
                    headers[Law] = i;
                }
                else if (stringHeaders[i].StartsWith("Tem", StringComparison.InvariantCultureIgnoreCase))
                {
                    headers[Temples] = i;
                }
                else if (stringHeaders[i].StartsWith("Gui", StringComparison.InvariantCultureIgnoreCase))
                {
                    headers[Guilds] = i;
                }
                else if (stringHeaders[i].StartsWith("Sou", StringComparison.InvariantCultureIgnoreCase))
                {
                    headers[Sources] = i;
                }
                else if (stringHeaders[i].StartsWith("Rac", StringComparison.InvariantCultureIgnoreCase))
                {
                    headers[Race] = i;
                }
                else if (stringHeaders[i].StartsWith("Pub", StringComparison.InvariantCultureIgnoreCase))
                {
                    headers[PublicInformation] = i;
                }
                else if (stringHeaders[i].StartsWith("Own", StringComparison.InvariantCultureIgnoreCase))
                {
                    headers[OwnerInformation] = i;
                }
                else if (stringHeaders[i].StartsWith("GM", StringComparison.InvariantCultureIgnoreCase))
                {
                    headers[GMInformation] = i;
                }
            }

            return headers;
        }

        protected override void FillEntity(DomainProvince entity, int index, int?[] headers, string[] data)
        {
            if (!headers[Province].HasValue)
            {
                return;
            }

            entity = entities
                        .Where(e => e.BaseProvince.Name.Equals(data[index + headers[Province].Value].Trim(), StringComparison.InvariantCultureIgnoreCase))
                        .FirstOrDefault();

            if (headers[Domain].HasValue)
            {
                entity.Domain = domains
                        .Where(
                            e =>
                            e.Name.Equals(data[index + headers[Domain].Value].Trim(),
                                                       StringComparison.InvariantCultureIgnoreCase))
                        .FirstOrDefault();
            }

            if (headers[Population].HasValue)
            {
                int value;
                if (int.TryParse(data[index + headers[Population].Value], out value))
                {
                    entity.PopulationLevel = value;
                }
            }

            if (headers[Fortification].HasValue)
            {
                int value;
                if (int.TryParse(data[index + headers[Fortification].Value], out value))
                {
                    entity.FortificationLevel = value;
                }
            }

            if (headers[Taxes].HasValue)
            {
                int value;
                if (int.TryParse(data[index + headers[Taxes].Value], out value))
                {
                    entity.Taxes = value;
                }
            }

            if (headers[Law].HasValue)
            {
                this.ParseLaw(entity, domains, data[index + headers[Law].Value]);
            }

            if (headers[Temples].HasValue)
            {
                this.ParseTemples(entity, domains, data[index + headers[Temples].Value]);
            }

            if (headers[Guilds].HasValue)
            {
                this.ParseGuilds(entity, domains, data[index + headers[Guilds].Value]);
            }

            if (headers[Sources].HasValue)
            {
                this.ParseSources(entity, domains, data[index + headers[Sources].Value]);
            }

            if (headers[Race].HasValue)
            {
                entity.Race = races
                        .Where(
                            e =>
                            e.Name.Equals(data[index + headers[Race].Value].Trim(),
                                                       StringComparison.InvariantCultureIgnoreCase))
                        .FirstOrDefault();
            }

            if (headers[PublicInformation].HasValue)
            {
                entity.PublicInformation = data[index + headers[PublicInformation].Value];
            }

            if (headers[OwnerInformation].HasValue)
            {
                entity.PublicInformation = data[index + headers[OwnerInformation].Value];
            }

            if (headers[GMInformation].HasValue)
            {
                entity.GMInformation = data[index + headers[GMInformation].Value];
            }
        }

        private void ParseLaw(DomainProvince province, IEnumerable<Domain> domains, string holdingsString)
        {
            var splitHoldings = holdingsString.Split(new string[] { "/", ",", "|" }, StringSplitOptions.RemoveEmptyEntries);

            foreach (var holdingString in splitHoldings)
            {
                string domainString;
                int level, fortification, visibility;
                this.ParseHolding(holdingString, out domainString, out level, out fortification, out visibility);

                var domain = domains.FirstOrDefault(e => e.Abbreviation.Equals(domainString, StringComparison.InvariantCultureIgnoreCase));
                if (domain != null)
                {
                    var holding = province.LawHoldings.AddNew();
                    holding.Visibility = visibility;
                    holding.Owner = domain;
                    holding.Level = level;
                    holding.FortificationLevel = fortification;
                }
            }
        }

        private void ParseTemples(DomainProvince province, IEnumerable<Domain> domains, string holdingsString)
        {
            var splitHoldings = holdingsString.Split(new string[] { "/", ",", "|" }, StringSplitOptions.RemoveEmptyEntries);

            foreach (var holdingString in splitHoldings)
            {
                string domainString;
                int level, fortification, visibility;
                this.ParseHolding(holdingString, out domainString, out level, out fortification, out visibility);

                var domain = domains.FirstOrDefault(e => e.Abbreviation.Equals(domainString, StringComparison.InvariantCultureIgnoreCase));
                if (domain != null)
                {
                    var holding = province.TempleHoldings.AddNew();
                    holding.Visibility = visibility;
                    holding.Owner = domain;
                    holding.Level = level;
                    holding.FortificationLevel = fortification;
                }
            }
        }

        private void ParseGuilds(DomainProvince province, IEnumerable<Domain> domains, string holdingsString)
        {
            var splitHoldings = holdingsString.Split(new string[] { "/", ",", "|" }, StringSplitOptions.RemoveEmptyEntries);

            foreach (var holdingString in splitHoldings)
            {
                string domainString;
                int level, fortification, visibility;
                this.ParseHolding(holdingString, out domainString, out level, out fortification, out visibility);

                var domain = domains.FirstOrDefault(e => e.Abbreviation.Equals(domainString, StringComparison.InvariantCultureIgnoreCase));
                if (domain != null)
                {
                    var holding = province.GuildHoldings.AddNew();
                    holding.Visibility = visibility;
                    holding.Owner = domain;
                    holding.Level = level;
                    holding.FortificationLevel = fortification;
                }
            }
        }

        private void ParseSources(DomainProvince province, IEnumerable<Domain> domains, string holdingsString)
        {
            var splitHoldings = holdingsString.Split(new string[] { "/", ",", "|" }, StringSplitOptions.RemoveEmptyEntries);

            foreach (var holdingString in splitHoldings)
            {
                string domainString;
                int level, fortification, visibility;

                this.ParseHolding(holdingString, out domainString, out level, out fortification, out visibility);

                var domain = domains.FirstOrDefault(e => e.Abbreviation.Equals(domainString, StringComparison.InvariantCultureIgnoreCase));
                if (domain != null)
                {
                    var holding = province.SourceHoldings.AddNew();
                    holding.Visibility = visibility;
                    holding.Owner = domain;
                    holding.Level = level;
                }
            }
        }

        private void ParseHolding(string holding, out string domain, out int level, out int fortification, out int visibility)
        {
            var firstSplit = holding.Split(new string[] { "(" }, StringSplitOptions.RemoveEmptyEntries);
            domain = firstSplit[0].Trim();

            int.TryParse(firstSplit[1].Substring(0, firstSplit[1].IndexOf(")")), out level);

            var split = firstSplit[1].Split(new string[] { "[" }, StringSplitOptions.RemoveEmptyEntries);
            // There is fortification data
            if (split.Length != 1)
            {
                int.TryParse(split[1].Substring(0, split[1].IndexOf("]")), out fortification);
            }
            else
            {
                fortification = 0;
            }

            // There is visibility data
            split = firstSplit[1].Split(new string[] { "{" }, StringSplitOptions.RemoveEmptyEntries);
            if (split.Length != 1)
            {
                int.TryParse(split[1].Substring(0, split[1].IndexOf("}")), out visibility);
            }
            else
            {
                visibility = 1;
            }
        }
    }
}
